﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Threading.Tasks;
using RaytracerLib.MathLib;
using RaytracerLib.Samplers;
using System.Collections.Concurrent;
using NLog;
using RaytracerLib.Postprocessing.LightCorrector;
using TomanuExtensions;
using RaytracerLib.Rays;
using System.Threading;
using RaytracerLib.Resamplers;
using YAXLib;
using RaytracerLib.Postprocessing;
using RaytracerLib.Layers;

namespace RaytracerLib.Renderers
{
    public class SamplesPeriodogramRenderer : Renderer
    {
        [YAXNode]
        public int Repeats = 100;

        [YAXNode]
        public int ScaleSamples = 25;

        [YAXNode]
        public double ScaleValues = 0.01;

        ColorArrayFloat m_periodogram;

        public override void Render()
        {
            m_periodogram = new ColorArrayFloat(Film.Width, Film.Height);

            for (int i = 0; i < Repeats; i++)
            {
                m_rects_to_update.Enqueue(Film.GetFilmRect());
                DoUpdateCallback();

                Scene scene = Scene.DeepClone();
                scene.RenderOptions.Renderer = Renderer.Create(RendererType.SamplesVisualizer);
                (scene.RenderOptions.Renderer as SamplesVisualizerRenderer).Scale = ScaleSamples;
                scene.ActiveCamera.Film.Postprocessors.Add(new FFT2Transform());
                
                if (i != 0)
                    (scene.ActiveCamera.Film.Resampler as ExactResampler).SuppressLog = true;

                if ((i % 5 == 0) && (i > 0))
                    Loggers.Raytracer.Info("Periodogram progress: {0}", i * Repeats / 100);

                Renderer renderer = scene.CreateRenderer();
                (renderer as SamplesVisualizerRenderer).SuppressLog = true;
                renderer.ShouldStop += () => DoShouldStop();
                renderer.Render();

                ColorArrayFloat part = renderer.Canvas.PostprocessedArray;

                foreach (var p in part.Pixels())
                    m_periodogram[p.X, p.Y] += part[p.X, p.Y] * ScaleValues;

                m_rects_to_update.Enqueue(Film.GetFilmRect());
                DoUpdateCallback();

                if (DoShouldStop())
                    break;
            }
        }

        public override void UpdateBitmap(Bitmap a_bmp)
        {
            using (Graphics g = Graphics.FromImage(a_bmp))
            {
                Rectangle rect;
                while (m_rects_to_update.TryDequeue(out rect))
                {
                    Bitmap bmp = m_periodogram.GetBitmap(rect);
                    g.DrawImage(bmp, rect);
                }
            }
        }

        public override RendererType RendererType
        {
            get
            {
                return RendererType.SamplerPeriodogram;
            }
        }
    }
}